package com.celesea.configuration.security;

import com.alibaba.fastjson.JSON;
import com.celesea.framework.api.HttpKit;
import com.celesea.framework.api.Tip;
import com.google.common.collect.Maps;
import org.jasig.cas.client.util.CommonUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.security.cas.ServiceProperties;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Map;

public class CustomCasAuthenticationEntryPoint implements AuthenticationEntryPoint, InitializingBean {

    private static Logger logger = LoggerFactory.getLogger(CustomCasAuthenticationEntryPoint.class);

    private static final String URL = "url";

    private ServiceProperties serviceProperties;
    private String loginUrl;
    private boolean encodeServiceUrlWithSessionId = true;

    public CustomCasAuthenticationEntryPoint() {
    }

    public void afterPropertiesSet() throws Exception {
        Assert.hasLength(this.loginUrl, "loginUrl must be specified");
        Assert.notNull(this.serviceProperties, "serviceProperties must be specified");
        Assert.notNull(this.serviceProperties.getService(), "serviceProperties.getService() cannot be null.");
    }

    public final void commence(
            HttpServletRequest request,
            HttpServletResponse response,
            AuthenticationException e) throws IOException, ServletException {
        logger.info("<<<<<<<<<<<<<<<<<==未授权:{}==>>>>>>>>>>>>>>>>>>",request.getRequestURI());
        String urlEncodedService = this.createServiceUrl(request, response);
        String redirectUrl = this.createRedirectUrl(urlEncodedService);

        if(StringUtils.isEmpty(request.getHeader("x-requested-with"))){
            this.preCommence(request, response);
            response.sendRedirect(redirectUrl);
        }else{
            writeJson(response, redirectUrl);
        }
    }

    private void writeJson(HttpServletResponse response, String redirectUrl) throws IOException {
        Tip<Object> tip = HttpKit.unlogin();
        // 放入需要前端重定向的sso地址
        Map<String, Object> map = Maps.newHashMap();
        map.put(URL, redirectUrl);
        tip.setContent(map);
        response.getOutputStream().write(JSON.toJSONString(tip).getBytes());
    }


    protected String createServiceUrl(HttpServletRequest request, HttpServletResponse response) {
        return CommonUtils.constructServiceUrl(
                (HttpServletRequest)null,
                response,
                this.serviceProperties.getService(),
                (String)null,
                this.serviceProperties.getArtifactParameter(),
                this.encodeServiceUrlWithSessionId);
    }

    protected String createRedirectUrl(String serviceUrl) {
        return CommonUtils.constructRedirectUrl(
                this.loginUrl,
                this.serviceProperties.getServiceParameter(),
                serviceUrl,
                this.serviceProperties.isSendRenew(),
                false);
    }

    protected void preCommence(HttpServletRequest request, HttpServletResponse response) {
    }

    public final String getLoginUrl() {
        return this.loginUrl;
    }

    public final ServiceProperties getServiceProperties() {
        return this.serviceProperties;
    }

    public final void setLoginUrl(String loginUrl) {
        this.loginUrl = loginUrl;
    }

    public final void setServiceProperties(ServiceProperties serviceProperties) {
        this.serviceProperties = serviceProperties;
    }

    public final void setEncodeServiceUrlWithSessionId(boolean encodeServiceUrlWithSessionId) {
        this.encodeServiceUrlWithSessionId = encodeServiceUrlWithSessionId;
    }

    protected boolean getEncodeServiceUrlWithSessionId() {
        return this.encodeServiceUrlWithSessionId;
    }
}
